﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyOnlineScheduling
{
    class Processor
    {
        public List<PartTask> taskList;
        public int endTime;
        public double weightedEndTime;
        public double weightedTimeRemaining;

        public int lastArrivalTime;

        public Processor()
        {
            taskList = new List<PartTask>();
            endTime = 0;
            weightedEndTime = 0.0;
            weightedTimeRemaining = 0.0;
            
            lastArrivalTime = 0;
        }

        public void calculateWeightedTimeRemaining(int currentTime)
        {
            int timeLeft = endTime - currentTime;
            int lastIndex = taskList.Count - 1;

            if (lastIndex < 0) weightedTimeRemaining = 0.0;
            else weightedTimeRemaining = (double)timeLeft / taskList[lastIndex].weight;
        }

        public void clearProcessor()
        {
            taskList.Clear();
            endTime = 0;
            weightedEndTime = 0.0;
            weightedTimeRemaining = 0.0;

            lastArrivalTime = 0;
        }

        public void display(int i)
        {
            Console.WriteLine("\n\nPROCESOR {0}\n", i);
            Console.WriteLine("ZADANIA");
            for (int j = 0; j < taskList.Count; j++)
            {
                taskList[j].displayTask(j);
            }
            Console.WriteLine("CZAS UKOŃCZENIA: {0}", endTime);
            Console.WriteLine("WAŻONY CZAS UKOŃCZENIA: {0}", weightedEndTime);
        }

        public void scheduleTaskOnProcessor(PartTask incomingTask, int currentTime)
        {
            endTime = currentTime + incomingTask.pendingPartDuration;

            double weightedTaskTime = (double)endTime * (double)incomingTask.weight;
            weightedEndTime += weightedTaskTime;

            incomingTask.partDoneNow = incomingTask.pendingPartDuration;
            incomingTask.completedPartDuration += incomingTask.pendingPartDuration;
            incomingTask.pendingPartDuration = 0;

            incomingTask.arrivalTime = currentTime;

            lastArrivalTime = currentTime;

            taskList.Add(incomingTask);
            calculateWeightedTimeRemaining(currentTime);
        }

        public PartTask expropriateTaskWithCheck(PartTask newTask, int currentTime)
        {
            int timeLeftToFinishLastTask = endTime - currentTime;
            if(timeLeftToFinishLastTask < 0) return null;

            int lastIndex = taskList.Count - 1;
            PartTask expropriatedTask = taskList.ElementAt<PartTask>(lastIndex);

            //if (timeLeftToFinishLastTask > expropriatedTask.completedPartDuration)
            //    return null;

            //if (newTask.arrivalTime == expropriatedTask.arrivalTime) 
            //    return null;

            double newWeightedEndTime, oldWeightedEndTime = weightedEndTime;
            int newEndTime;

            weightedEndTime -= (double)endTime * (double)expropriatedTask.weight;
            endTime = currentTime;

            newEndTime = currentTime + newTask.pendingPartDuration;
            newWeightedEndTime = weightedEndTime + (double)newEndTime * (double)newTask.weight;

            if (newWeightedEndTime > oldWeightedEndTime)
            {
                endTime = currentTime + timeLeftToFinishLastTask;
                weightedEndTime += (double)endTime * (double)expropriatedTask.weight;
                return null;
            }

            taskList.RemoveAt(lastIndex);

            expropriatedTask.completedPartDuration -= timeLeftToFinishLastTask;
            expropriatedTask.partDoneNow -= timeLeftToFinishLastTask;
            expropriatedTask.pendingPartDuration += timeLeftToFinishLastTask;

            taskList.Add(expropriatedTask);
            PartTask partialTask = new PartTask(expropriatedTask);

            calculateWeightedTimeRemaining(currentTime);

            return partialTask;
        }

        public PartTask expropriateTask(int currentTime)
        {
            int timeLeftToFinishLastTask = endTime - currentTime;
            if (timeLeftToFinishLastTask < 0) return null;

            int lastIndex = taskList.Count - 1;
            PartTask expropriatedTask = taskList.ElementAt<PartTask>(lastIndex);

            weightedEndTime -= (double)endTime * (double)expropriatedTask.weight;
            endTime = currentTime;

            taskList.RemoveAt(lastIndex);

            expropriatedTask.completedPartDuration -= timeLeftToFinishLastTask;
            expropriatedTask.partDoneNow -= timeLeftToFinishLastTask;
            expropriatedTask.pendingPartDuration += timeLeftToFinishLastTask;

            taskList.Add(expropriatedTask);
            PartTask partialTask = new PartTask(expropriatedTask);

            partialTask.arrivalTime = currentTime;

            calculateWeightedTimeRemaining(currentTime);

            return partialTask;
        }
    }
}
